package org.ymh.unix_file_system.dao;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.ymh.unix_file_system.domain.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Stack;


@Component
public class FileSystemOperate {
    @Autowired
    public VisitingRecordOperate visitingRecordOperate;
    @Autowired
    public JsonDataOperate jsonDataOperate;
    @Autowired
    public GlobalVariable globalVariable;
    @Autowired
    public BlockOperate blockOperate;
    @Autowired
    public InodeOperate inodeOperate;
    @Autowired
    public IndexOperate indexOperate;
    @Autowired
    public FreeBlockLinkedListOperate freeBlockLinkedListOperate;
    @Autowired
    public DirNodeOperate dirNodeOperate;
    /**
    * @Description 引导块初始化整个文件系统
    * @Author  lenovo
    * @Date   2023/12/18 0:00
    * @Param
    * @Return
    * @Exception
    */

    public void initByGuideBlock()//
    {
        ArrayList<String> superPath=new ArrayList<>();//超级块所占
        ArrayList<String>  inodePath= new ArrayList<>();//i节点所占
        ArrayList<String>  rootDirPath= new ArrayList<>();//
        ArrayList<String>  blockBitMapPath= new ArrayList<>();//根节点块数
        ArrayList<String>  inodeBitMapPath= new ArrayList<>();//根节点块数


        //初始化super块和全局变量
        globalVariable.setError(null);
        globalVariable.superBlock=new SuperBlock();
        globalVariable.superBlock.singeFileMaxSize=globalVariable.foundation.singleFileMaxSize;
        globalVariable.superBlock.fileSystemSize= globalVariable.foundation.fileSystemSize;
        globalVariable.superBlock.fileSystemRestSize= globalVariable.foundation.fileSystemSize;
        globalVariable.superBlock.blockSize= globalVariable.foundation.blockSize;
        globalVariable.superBlock.inodeSize = globalVariable.foundation.inodeSize;
        globalVariable.superBlock.dirItemSize = globalVariable.foundation.dirItemSize;
        globalVariable.superBlock.inodeCountSum = (int) Math.floor(globalVariable.foundation.inodeBlockCount*1.0* globalVariable.superBlock.blockSize*1024/  globalVariable.superBlock.inodeSize);//B相除,并向下取整
        globalVariable.superBlock.blockCountSum = (int) (  globalVariable.superBlock.fileSystemRestSize/  globalVariable.superBlock.blockSize);
        globalVariable.superBlock.blockCountRest =  globalVariable.superBlock.blockCountSum;
        globalVariable.superBlock.inodeCountRest =  globalVariable.superBlock.inodeCountSum;
        globalVariable.rootDirNode=new DirNode();//为全局变量做初始化
        visitingRecordOperate.initRootItem();//访问栈初始化
        globalVariable.blockBitMap=new boolean[globalVariable.superBlock.blockCountSum];
        globalVariable.inodeBitMap=new boolean[globalVariable.superBlock.inodeCountSum];
        globalVariable.inodeArray=new INode[globalVariable.superBlock.inodeCountSum];
        //空闲的只有数据盘
        for (int i = 0; i < globalVariable.foundation.superBlockCount; i++) {
            int num= globalVariable.foundation.superBlockStart+i;
            blockOperate.blockAllocate(num);
            superPath.add(""+num);
        }
        for (int i = 0; i < globalVariable.foundation.inodeBlockCount; i++) {
            int num= globalVariable.foundation.inodeBlockStart+i;
            blockOperate.blockAllocate(num);
            inodePath.add(""+num);
        }
        for (int i = 0; i < globalVariable.foundation.rootDirBlockCount; i++) {
            int num= globalVariable.foundation.rootDirBlockStart+i;
            blockOperate.blockAllocate(num);
            rootDirPath.add(""+num);
        }

        int inodeOccupy= (int) Math.ceil(globalVariable.superBlock.inodeCountSum*1.0/8/(globalVariable.foundation.inodeSize*1024));//计算占距的物理块
        int blockOccupy= (int) Math.ceil(globalVariable.superBlock.blockCountSum*1.0/8/(globalVariable.foundation.blockSize*1024));
        globalVariable.superBlock.blockBitMapLocation=new int[blockOccupy];
        globalVariable.superBlock.inodeBitMapLocation=new int[inodeOccupy];
        int count= globalVariable.foundation.dataBlockStart;
        for (int i = 0; i <   blockOccupy; i++) {
            globalVariable.superBlock.blockBitMapLocation[i]=count;
            blockBitMapPath.add(""+count);
            blockOperate.blockAllocate(count);
            count++;
        }
        for (int i = 0; i < inodeOccupy; i++) {
            globalVariable.superBlock.inodeBitMapLocation[i]=count;
            inodeBitMapPath.add(count+"");
            blockOperate.blockAllocate(count);
            count++;
        }
        //分配物理块(超级块，inode，位图，根节点）
        jsonDataOperate.jsonFileStringify(globalVariable.inodeArray,inodePath.toArray(new String[0]));
        jsonDataOperate.jsonFileStringify(globalVariable.rootDirNode,rootDirPath.toArray(new String[0]));
        jsonDataOperate.superJsonFileStringify(globalVariable.superBlock,superPath.toArray(new String[0]));
        jsonDataOperate.jsonFileStringify(globalVariable.blockBitMap,blockBitMapPath.toArray(new String[0]));
        jsonDataOperate.jsonFileStringify(globalVariable.inodeBitMap,inodeBitMapPath.toArray(new String[0]));


        //初始化成组链接
        globalVariable.rootStack=new FreeBlockLinkedList();
        for (int i = 0; i < globalVariable.blockBitMap.length; i++) {
            if(!globalVariable.blockBitMap[i])
            {
                freeBlockLinkedListOperate.addFreeBlock(new short[]{(short) i});

            }
        }
//初始化当前节点

    }
    /**
    * @Description 读入已有盘块来初始化
    * @Author  lenovo
    * @Date   2023/12/18 0:00
    * @Param
    * @Return
    * @Exception
    */

    public void initByJson()
    {
        //写入super块
       globalVariable.superBlock=jsonDataOperate.jsonFileParse(new SuperBlock(),globalVariable.foundation.superBlockStart+"");
       //写入Inode数组
        globalVariable.inodeArray=jsonDataOperate.jsonFileParse(new INode[]{},globalVariable.foundation.inodeBlockStart+"");
        //写入根节点
        globalVariable.rootDirNode=jsonDataOperate.jsonFileParse(new DirNode(),globalVariable.foundation.rootDirBlockStart+"");
        visitingRecordOperate.initRootItem();
        //
        globalVariable.blockBitMap=jsonDataOperate.jsonFileParse(new boolean[]{},globalVariable.superBlock.blockBitMapLocation[0]+"");
        globalVariable.inodeBitMap=jsonDataOperate.jsonFileParse(new boolean[]{},globalVariable.superBlock.inodeBitMapLocation[0]+"");
        globalVariable.setError(null);
        //初始化一些东西
        globalVariable.rootStack=new FreeBlockLinkedList();
        //成组链接(倒着好像更好看）
        for (int i = globalVariable.blockBitMap.length-1; i >=0 ; i--) {
            if(!globalVariable.blockBitMap[i])
                freeBlockLinkedListOperate.addFreeBlock(new short[]{(short)i});
        }

    }
    /**
    * @Description 创建一个普通文件
    * @Author  lenovo
    * @Date   2023/12/17 13:37
    * @Param
    * @Return
    * @Exception
    */

    public boolean createFile(String name,Long B)
    {

            INode iNode = new INode((byte) 0);
            iNode=indexOperate.createIndex(B);
            if(iNode==null)
                return false;
            iNode.setFileLength((int) Math.ceil(B*1.0/1024));
            iNode.setCount((byte) 1);
            DirItem dirItem = new DirItem();
            int freeNodeNumber = inodeOperate.getFreeNodeNumber();
            if(freeNodeNumber!=-1)
            {
                dirItem.setFileName(name);
                dirItem.setInodeNumber(freeNodeNumber);
                //分配空间
                inodeOperate.inodeAllocation(freeNodeNumber,iNode);
                return dirNodeOperate.addFileItem(dirItem);
            }
            return true;
    }
    /**
    * @Description 创建一个目录（占的空间为该目录下的目录项占的空间）
    * @Author  lenovo
    * @Date   2023/12/17 13:38
    * @Param
    * @Return
    * @Exception
    */

    public boolean createDir(String name)//根目录建立目录
    {
        INode iNode = new INode();
        int freeNodeNumber = inodeOperate.getFreeNodeNumber();
        if(freeNodeNumber!=-1)
        {
            iNode = indexOperate.createIndex(1024L * globalVariable.foundation.dirOccupyBlockSize);
            if(iNode==null)//创建失败
                return false;
            iNode.setType((byte) 1);
            iNode.setCount((byte) 1);
            inodeOperate.inodeAllocation(freeNodeNumber,iNode);
            DirItem dirItem = new DirItem();
            dirItem.setFileName(name);
            dirItem.setInodeNumber(freeNodeNumber);
            //创建成功后将目录节点绑定在inode节点里写入
            DirNode dirNode = new DirNode();
            jsonDataOperate.jsonFileStringify(dirNode,new String[]{iNode.getAddress()[0]+""});
            return dirNodeOperate.addFileItem(dirItem);
        }
        return false;
    }
    public void saveDate()
    {
        jsonDataOperate.superJsonFileStringify(globalVariable.superBlock,new String[]{globalVariable.foundation.superBlockStart+""});
        jsonDataOperate.jsonFileStringify(globalVariable.blockBitMap,new String[]{globalVariable.superBlock.blockBitMapLocation[0]+""});
        jsonDataOperate.jsonFileStringify(globalVariable.inodeBitMap,new String[]{globalVariable.superBlock.inodeBitMapLocation[0]+""});
        jsonDataOperate.jsonFileStringify(globalVariable.rootDirNode,new String[]{globalVariable.foundation.rootDirBlockStart+""});
        jsonDataOperate.jsonFileStringify(globalVariable.inodeArray,new String[]{globalVariable.foundation.inodeBlockStart+""});
        //保存当前文件
        jsonDataOperate.jsonFileStringify(globalVariable.visitingRecord.peek().dirNode,new String[]{globalVariable.visitingRecord.peek().inode.getAddress()[0]+""});
    }

    /**
    * @Description 删除当前的某个文件
    * @Author  lenovo
    * @Date   2023/12/18 1:32
    * @Param
    * @Return
    * @Exception
    */

    public boolean deleteFile(String path)
    {
        DirItem fileItem = dirNodeOperate.findFileItem(globalVariable.visitingRecord.peek().dirNode, path);
        if(fileItem==null)
        {
            return false;
        }
        else{
            dirNodeOperate.deleteFileItem(path);return true;
        }


    }
    public HashMap<String, Object> re()
    {
        visitingRecordOperate.pop();//回退一个
            HashMap<String, Object> map = JsonDate(indexOperate.getOccupyBlockByInode(globalVariable.visitingRecord.peek().inode),
                    globalVariable.visitingRecord.peek().dirNode,globalVariable.getError());
            globalVariable.visitingRecord.peek();
            return map;
    }
    /**
     * @Description 进入对应文件夹(打开 ， 若是普通文件 ， 不改变当前位置 ）
     * @Author lenovo
     * @Date 2023/12/18 0:01
     * @Param
     * @Return
     * @Exception
     */
    public HashMap<String, Object> cd(String name)
    {
        DirItem fileItem = dirNodeOperate.findFileItem(globalVariable.visitingRecord.peek().dirNode,name);
        if(fileItem!=null)
        {
            INode iNode = globalVariable.inodeArray[fileItem.inodeNumber];
            if(iNode.getType()==0){
                HashMap<String, LinkedList<Integer>> occupyBlockByInode = indexOperate.getOccupyBlockByInode(iNode);
                    return JsonDate(occupyBlockByInode,globalVariable.visitingRecord.peek().dirNode,globalVariable.getError());
            }
            else if(iNode.getType()==1){
            visitingRecordOperate.push(fileItem.inodeNumber);//加入栈
                    return JsonDate(indexOperate.getOccupyBlockByInode(iNode),globalVariable.visitingRecord.peek().dirNode,globalVariable.getError());
            }
        }
        return null;
    }
    public HashMap<String,Object> JsonDate(Object allocateCondition,Object dirNode,Object error)
    {

        ArrayList<Boolean> list=null;
        if(dirNode!=null) {
            list = new ArrayList<>();
            DirNode node=(DirNode) dirNode;
            for (int i = 0; i < node.childFile.size(); i++) {
                byte type = globalVariable.inodeArray[node.childFile.get(i).inodeNumber].type;
                if(type==0)
                    list.add(true);
                else if(type==1)
                    list.add(false);
            }
        }
        HashMap<String,Object> map = new HashMap<>();
        map.put("allocateCondition",allocateCondition);
        map.put("dirNode",dirNode);
        map.put("isFile",list);
        map.put("error",error);
        return map;
    }
}
